﻿using System;
using System.Collections.Generic;
using System.ServiceModel;
using System.ServiceModel.Web;
using Interscape.TwilioClient.Components;
using Interscape.TwilioClient.ServiceHelpers;
using Microsoft.Http;

namespace Interscape.TwilioClient
{

    #region Service Interface

    [ServiceContract]
    public interface ICallManager
    {
        [OperationContract]
        [TwilioWcfSerializer]
        [WebGet(
            BodyStyle = WebMessageBodyStyle.WrappedResponse,
            ResponseFormat = WebMessageFormat.Xml,
            UriTemplate = "/Accounts/{accountSid}/Calls"
            )]
        PhoneCallList GetAll(string accountSid);

        [OperationContract]
        [TwilioWcfSerializer]
        [WebGet(
            BodyStyle = WebMessageBodyStyle.WrappedResponse,
            ResponseFormat = WebMessageFormat.Xml,
            UriTemplate = "/Accounts/{accountSid}/Calls/{callId}"
            )]
        PhoneCall Get(string accountSid, string callId);
    }

    #endregion

    /// <summary>
    /// 
    /// </summary>
    public class CallManager : ManagerBase<ICallManager>, ICallManager
    {

        #region Constructors

        /// <summary>
        /// Creates a new instance of the CallManager.
        /// </summary>
        /// <param name="accountSid">The 34 character string that uniquely identifies the Account which will be used to make the TwilioAPI requests.</param>
        /// <param name="authToken">The "password" for your Twilio API calls.</param>
        public CallManager(string accountSid, string authToken) : base(accountSid, authToken)
        {
        }

        #endregion

        /// <summary>
        /// Returns a list of phone calls made by your account. The list is sorted by DateUpdated, with newest calls first.
        /// </summary>
        /// <returns></returns>
        public PhoneCallList GetAll()
        {
            return this.GetAll(this.AccountSid);
        }

        /// <summary>
        /// Returns a list of phone calls made by your account. The list is sorted by DateUpdated, with newest calls first.
        /// </summary>
        /// <param name="accountSid">A 34 character string that uniquely identifies the Account associated with this resource.</param>
        /// <returns></returns>
        public PhoneCallList GetAll(string accountSid)
        {
            return this.Channel.GetAll(accountSid);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="callId"></param>
        /// <returns></returns>
        public PhoneCall Get(string callId)
        {
            return this.Get(this.AccountSid, callId);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="accountSid">A 34 character string that uniquely identifies the Account associated with this resource.</param>
        /// <param name="callId"></param>
        /// <returns></returns>
        public PhoneCall Get(string accountSid, string callId)
        {
            return this.Channel.Get(accountSid, callId);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="callerId"></param>
        /// <param name="numberToCall"></param>
        /// <param name="url"></param>
        /// <returns></returns>
        public PhoneCall PlaceCall(string callerId, string numberToCall, string url)
        {
            PhoneCall call = new PhoneCall();
            call.Caller = callerId;
            call.Called = numberToCall;
            call.PostArguments.Add("Url", url);
            return this.PlaceCall(call);
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="call"></param>
        /// <returns></returns>
        /// <example>
        /// 
        /// </example>
        /// <remarks>
        /// Url, Method, SendDigits (0-9, #, *), IfMachine (Continue, Hangup), Timeout (0-999, Default 60)
        /// </remarks>
        public PhoneCall PlaceCall(PhoneCall call)
        {

            System.Net.ServicePointManager.Expect100Continue = false;
            HttpUrlEncodedForm form = new HttpUrlEncodedForm();

            //Validate the required properties
            if (string.IsNullOrEmpty(call.Caller)) throw new ArgumentNullException("The \"Caller\" property must be set in order to place an outgoing call.");
            if (string.IsNullOrEmpty(call.Called)) throw new ArgumentNullException("The \"Caller\" property must be set in order to place an outgoing call.");
            if ((call.PostArguments.Count < 1) || (!call.PostArguments.ContainsKey("Url")))
            {
                throw new ArgumentNullException("The \"Url\" parameter must be added to Call.PostArguments in order to place an outgoing call.");
            }

            //Passed validation, add the data to the Form POST
            form.Add("Caller", call.Caller);
            form.Add("Called", call.Called);
            foreach (KeyValuePair<string, string> arg in call.PostArguments)
            {
                if ((arg.Key == "SendDigits") && (arg.Value.Contains("#")))
                {
                    //The method caller neglected to UrlEncode the string. That's ok, we'll do it for them.
                    form.Add(arg.Key, HttpUtility.UrlEncode(arg.Value));
                }
                else
                {
                    form.Add(arg.Key, arg.Value);
                }
            }

            //Submit the POST and process the response
            HttpResponseMessage response = this.HttpClientHelper.Post(this.Urls.CallsUrl(true), form.CreateHttpContent());
            return (PhoneCall)ServiceUtility.ProcessHttpResponseMessage(response, typeof(PhoneCall));
        }

    }
}
